#include "gpu_render.hpp"
#ifndef __SYNTHESIS__
#include <iostream>
#endif

// 辅助函数：将常量参数推送到 stream
void stream_constants(
    const ap_uint<16> num_triangles,
    const ap_uint<11> max_x,
    const ap_uint<11> max_y,
    hls::stream<ap_uint<16>>& s_num_triangles,
    hls::stream<ap_uint<11>>& s_max_x,
    hls::stream<ap_uint<11>>& s_max_y
) {
    // 移除 INLINE pragma，避免与 DATAFLOW 冲突警告
    s_num_triangles.write(num_triangles);
    s_max_x.write(max_x);
    s_max_y.write(max_y);
}

void GPU_Render_TBR(
    ddr_word_t* params_buffer_base_addr,
    const ap_uint<16> num_triangles_to_process,
    const ap_uint<11> max_x_res,
    const ap_uint<11> max_y_res,
    zbuffer_ddr_word_t* zbuffer_ddr_raw_ptr, // 原始 AXI 指针
    color_ddr_word_t* framebuffer_ddr_raw_ptr, // 原始 AXI 指针
    ap_uint<32>& total_write_ops_processed
) {
    // --- 顶层 S_AXILITE 接口声明 ---
    // 统一 bundle 名称
    #pragma HLS INTERFACE s_axilite port=params_buffer_base_addr bundle=ctrl_s_axilite
    #pragma HLS INTERFACE s_axilite port=num_triangles_to_process bundle=ctrl_s_axilite
    #pragma HLS INTERFACE s_axilite port=max_x_res bundle=ctrl_s_axilite
    #pragma HLS INTERFACE s_axilite port=max_y_res bundle=ctrl_s_axilite
    // DDR 指针现在作为 AXI Master 接口的直接参数，而不是 S_AXILITE 控制寄存器
    #pragma HLS INTERFACE s_axilite port=total_write_ops_processed bundle=ctrl_s_axilite
    #pragma HLS INTERFACE s_axilite port=return bundle=ctrl_s_axilite

    // --- M_AXI 接口声明 ---
    // 计算深度：
    // framebuffer: 640 * 480 pixels / 2 pixels_per_word (each pixel occupies a 32-bit slot) = 153600 words
    // params_buffer: MAX_NUM_TRIANGLES (1023) * NUM_AXI_WORDS_PER_PACKET (10) = 10230 words
    // zbuffer: 640 * 480 pixels / 4 z_per_word = 76800 words

    #pragma HLS INTERFACE m_axi port=params_buffer_base_addr    offset=slave bundle=m_axi_gmem_params_read   max_read_burst_length=256 latency=60 num_read_outstanding=16 num_write_outstanding=16 depth=10230
    // 将 DDR 指针直接绑定到 M_AXI 接口，并降低 outstanding 数量以节省 BRAM
    #pragma HLS INTERFACE m_axi port=zbuffer_ddr_raw_ptr      offset=slave bundle=m_axi_gmem_zb_rw         max_read_burst_length=256 max_write_burst_length=256 latency=60 num_read_outstanding=16 num_write_outstanding=16 depth=76800 // 修正 depth
    #pragma HLS INTERFACE m_axi port=framebuffer_ddr_raw_ptr offset=slave bundle=m_axi_gmem_fb_write max_read_burst_length=256 max_write_burst_length=256 latency=60 num_read_outstanding=16 num_write_outstanding=16 depth=153600 // 修正 depth

    // --- 声明共享 BRAM 数组 (在 DATAFLOW 区域之外) ---
    // 存储所有三角形数据 (由 Binning 写入，Rasterizer 读取)
    static binned_triangle_packet_fixed all_triangles_bram[MAX_NUM_TRIANGLES]; 
    #pragma HLS bind_storage variable=all_triangles_bram type=ram_t2p impl=bram 

    // 启用 DATAFLOW 优化，将各个子模块并行化
    #pragma HLS DATAFLOW

    // --- 内部 Stream 声明 ---
    // 连接 PBIRSM -> HR_TBR_Binning
    hls::stream<raster_params_packet_fixed> pbirsm_to_hr_tbr_stream("pbirsm_to_hr_tbr_stream");
    // 深度保持 8，因为其位宽较大，进一步降低可能导致 Dataflow 停顿
    #pragma HLS STREAM variable=pbirsm_to_hr_tbr_stream depth=8 

    // stream 用于传递常量 (给 Binning 模块)
    hls::stream<ap_uint<16>> s_num_triangles_to_process_const("s_num_triangles_to_process_const"); 
    hls::stream<ap_uint<11>> s_max_x_res_const("s_max_x_res_const"); 
    hls::stream<ap_uint<11>> s_max_y_res_const("s_max_y_res_const"); 

    // stream 用于传递 Tile List 数据从 Binning 模块到 Rasterizer 模块
    hls::stream<TileListDataPacket> s_tile_list_from_binning_to_rasterizer("s_tile_list_from_binning_to_rasterizer");
    // 降低 TileListDataPacket 的位宽后，其 BRAM 占用会降低。深度 256 保持不变以确保正确的数据传输。
    #pragma HLS STREAM variable=s_tile_list_from_binning_to_rasterizer depth=256

    // stream 用于传递分辨率参数从 Binning 模块到 Rasterizer 模块
    hls::stream<ap_uint<11>> s_max_x_res_from_binning_to_rasterizer("s_max_x_res_from_binning_to_rasterizer");
    hls::stream<ap_uint<11>> s_max_y_res_from_binning_to_rasterizer("s_max_y_res_from_binning_to_rasterizer");
    // stream 用于转发 num_triangles
    hls::stream<ap_uint<16>> s_num_triangles_from_binning_to_rasterizer("s_num_triangles_from_binning_to_rasterizer");

    #pragma HLS STREAM variable=s_num_triangles_to_process_const depth=4
    #pragma HLS STREAM variable=s_max_x_res_const depth=4
    #pragma HLS STREAM variable=s_max_y_res_const depth=4

    #pragma HLS STREAM variable=s_max_x_res_from_binning_to_rasterizer depth=4
    #pragma HLS STREAM variable=s_max_y_res_from_binning_to_rasterizer depth=4
    #pragma HLS STREAM variable=s_num_triangles_from_binning_to_rasterizer depth=4 

    // --- 实例化并连接子模块 ---

    // 0. Stream Constants (传递给 Binning 模块)
    // 直接传入顶层函数接收的常量参数
    stream_constants(
        num_triangles_to_process,
        max_x_res,
        max_y_res,
        s_num_triangles_to_process_const, // for binning
        s_max_x_res_const,                // for binning
        s_max_y_res_const                 // for binning
    );

    // 1. Parameter Buffer Interface and Raster Setup Manager (PBIRSM)
    parameter_buffer_interface_and_raster_setup(
        params_buffer_base_addr,
        pbirsm_to_hr_tbr_stream,
        num_triangles_to_process
    );

    // 2. HR_TBR_Binning_With_BRAM_Write (Triangle Binning & BRAM Write)
    //    现在它也负责将 Tile List 数据和常量流化输出
    hr_tbr_binning_with_bram_write(
        pbirsm_to_hr_tbr_stream,
        all_triangles_bram,      // 写入 BRAM
        s_max_x_res_const,       // 从 stream 读取
        s_max_y_res_const,       // 从 stream 读取
        s_num_triangles_to_process_const, // 从 stream 读取
        s_tile_list_from_binning_to_rasterizer, // 写入流 (Tile List 数据)
        s_max_x_res_from_binning_to_rasterizer, // 写入流 (转发分辨率)
        s_max_y_res_from_binning_to_rasterizer,  // 写入流 (转发分辨率)
        s_num_triangles_from_binning_to_rasterizer // 写入流 (转发 num_triangles)
    );

    // 3. TBR_Rasterizer_With_BRAM_Read (Tile-Based Rasterizer & BRAM Read)
    tbr_rasterizer_with_bram_read(
        all_triangles_bram,                       // 从 BRAM 读取
        s_tile_list_from_binning_to_rasterizer,   // 从流中读取 Tile List 数据
        s_num_triangles_from_binning_to_rasterizer, // 从 binning 模块转发的流中读取
        s_max_x_res_from_binning_to_rasterizer,     // 从 stream 读取 (转发分辨率)
        s_max_y_res_from_binning_to_rasterizer,     // 从 stream 读取 (转发分辨率)
        zbuffer_ddr_raw_ptr,                        // 原始 DDR 指针传递给 AXI 接口
        framebuffer_ddr_raw_ptr,                    // 原始 DDR 指针传递给 AXI 接口
        total_write_ops_processed
    );
}

